Enterprise Objects Framework Release 1.1 Copyright ã1995 by NeXT Computer, Inc.  All Rights Reserved.

EOFault

Inherits From:	none (EOFault is a root class)

Declared In:	eoaccess/EOFault.h

Class Description

An EOFault is an enterprise object (or an array of enterprise objects) whose data hasn't yet been fetched from the database. When an EODatabaseChannel fetches an object that has relationships, it creates EOFaults for the destinations of those relationships (unless, for to-one relationships, the corresponding objects have already been fetched and uniqued). By not fetching an object until the application actually needs it, the EODatabaseChannel prevents unnecessary interaction with the database server.

An EOFault can represent one object, in which case it's called a single-object fault, or it can represent an array of objects described by some qualifier, in which case it's called an array fault. To-one relationships result in single-object faults, while to-many relationships result in array faults. A single-object fault fetches and loads the real object over itself the first time you send a message to it (with some exceptions, listed below). An array fault loads its objects as soon as you send it any message that requires accessing the contents of the array (objectAtIndex:, count, and so on). EOFaults of either type are called fault objects.

The objectFaultWithPrimaryKey:entity:databaseChannel:zone: class method creates a single-object fault, and the arrayFaultWithQualifier:fetchOrder:databaseChannel:zone: class method creates an array fault. You can't create a fault object with alloc and init... messages.

Your application can explicitly create fault objects to avoid fetch conflicts. This is a concern for newly created enterprise objects that need to fetch objectsÐother than those given by their relationshipsÐin their takeValuesFromDictionary: or awakeForDatabaseChannel: methods (described in the EOKeyValueCoding and EODatabaseChannelNotification protocol specifications, respectively). Because the channel that fetched the enterprise object is busy, the enterprise object can't use it to fetch other objectsÐand must be careful not to access any objects that are actually fault objects. An enterprise object can use a different channel to fetch another object immediately, or it can create a fault object so that the instance variable at least contains a valid pointer.

A newly created enterprise object must not access a fault object while its channel is busy fetching. Doing so causes the fault to attempt a fetch with that channel, resulting in a fetch conflict. The enterprise object also can't replace a single-object fault with an object it fetches itself; the fault has already been uniqued by the time the enterprise object gets it, and other enterprise objects may hold references to it. An array fault, however, can be replaced; you might want to replace an array fault to change the qualifier or the fetch order that will be used to fetch its targets.

Messages that Don't Cause Fetching

A fault object responds to some messages as if it were the target object, without causing a fetch. For example, class returns the class of object that will be fetched, not the EOFault class. The following instance methods neither cause a fault object to fetch nor betray the true identity of a fault object:

autorelease
class
conformsToProtocol:
description
isKindOfClass:
isMemberOfClass:
isProxy (returns NO)
printForDebugger:
release
respondsToSelector:
retain
retainCount
zone

Forcing a Fault Object to Fetch

You can force a fault object to fetch by sending it a message that it can't handle as a fault. The messages listed in the previous section all work with generic run-time information, and so don't cause fetching, but any message that accesses data (such as the key-value coding method valuesForKeys: or a custom message such as lastName) causes the fault to fetch its data with its database channel. EOFault also defines the self message so that it always causes the fault to fetch; this provides you with a method that has no effect on a normal object, but that you can always use to cause a fault object to fetch. Remember that you shouldn't cause a fault to fetch itself if its database channel is busy.

With a single-object fault, you can conveniently use EODatabaseChannel's refetchObject: method to get the data for the fault. This technique allows you to fetch the fault's data even when its database channel is busy, by using a different database channel. refetchObject: checks whether it's fetching for a fault object, and transforms the fault into an instance of its enterprise object class.

Forcing a fetch on an array fault is best done by replacing the array fault with one that has a different database channel, and then causing the new fault to fetch itself:

id array;    /* Assume this exists and is an array fault. */
EODatabaseChannel *availableChannel;
id forcedFault;

forcedFault = [EOFault arrayFaultWithQualifier:[array qualifier]
    fetchOrder:[array fetchOrder]
    databaseChannel:availableChannel
    zone:[array zone]];

[array autorelease];
array = [[forcedFault self] retain];

This code excerpt creates a new array fault with the same information as the one being fetched, except that it's using a database channel that isn't busy fetching. It then sends self to the new fault to force it to fetch, and assigns it to the original variable.

In the event that the Framework is unable to resolve a to-one fault to a single database record (to-one relationships must resolve to exactly one record), unableToFaultWithPrimaryKey:entity:databaseChannel: is invoked; the default implementation of this method raises an exception. You can override this method in your enterprise objects to supply different behavior. See the description of the EOUnableToFaultToOne informal protocol elsewhere in this Reference for more information.

Instance Variables

Class isa;

isa	A pointer to the instance's class structure.

Method Types

Creating a fault	+ arrayFaultWithQualifier:fetchOrder:
databaseChannel:zone:
+ objectFaultWithPrimaryKey:entity:
databaseChannel:zone:

Getting information about a fault
+ clearFault:
+ databaseChannelForFault:
+ entityForFault:
+ fetchOrderForFault:
+ isFault:
+ primaryKeyForFault:
+ qualifierForFault:
+ targetClassForFault:

Special instance methods	- description
- self

Class Methods

arrayFaultWithQualifier:fetchOrder:databaseChannel:zone:

+ (NSArray *)arrayFaultWithQualifier:(EOQualifier *)aQualifier
fetchOrder:(NSArray *)aFetchOrder
databaseChannel:(EODatabaseChannel *)aChannel
zone:(NSZone *)zone

Returns an array fault that will have aChannel fetch its objects according to aQualifier and aFetchOrder (an array of EOAttributeOrdering objects) when it's accessed for the first time. If aChannel is fetching when the array is accessed, a fetch conflict will result, with undefined results.

See also:  + objectFaultWithPrimaryKey:entity:databaseChannel:zone

clearFault:

+ (void)clearFault:aFault

Turns aFault into a freshly initialized instance of the target class. Does not fetch data for the new instance. Raises NSInvalidArgumentException if invoked with an object that isn't a fault object. You should rarely need to use this method.

See also:  + targetClassForFault:

databaseChannelForFault:

+ (EODatabaseChannel *)databaseChannelForFault:aFault

Returns the EODatabaseChannel that aFault was created with, or nil if aFault isn't a fault object.

entityForFault:

+ (EOEntity *)entityForFault:aFault

Returns the entity that aFault was created with (or as determined by the qualifier for an array fault). Returns nil if aFault isn't a fault object.

fetchOrderForFault:

+ (NSArray *)fetchOrderForFault:aFault

Returns the array of EOAttributeOrdering objects that aFault was created with, or nil if aFault isn't an array fault.

isFault:

+ (BOOL)isFault:anObject

Returns YES if anObject is a fault object, NO otherwise. You should use this method, not isKindOfClass:, if you need to know whether an object is in fact a fault object.

objectFaultWithPrimaryKey:entity:databaseChannel:zone:

+ objectFaultWithPrimaryKey:(NSDictionary *)aKey
entity:(EOEntity *)anEntity
databaseChannel:(EODatabaseChannel *)aChannel
zone:(NSZone *)zone

Returns a single-object fault for an enterprise object with the specified primary key and entity. When accessed, aChannel fetches the actual object for the fault, allocating it from zone. If aChannel is fetching when the fault attempts to fetch, a fetch conflict will result, with undefined results.

See also:  + arrayFaultWithQualifier:fetchOrder:databaseChannel:zone

primaryKeyForFault:

+ (NSDictionary *)primaryKeyForFault:aFault

Returns the primary key for a single-object fault, nil for an array fault or non-fault object.

qualifierForFault:

+ (EOQualifier *)qualifierForFault:aFault

Returns the qualifier used to fetch the object or objects that aFault was created for. For a single-object fault this is the qualifier of the entity the fault was created with, plus the primary key specification; for an array fault this is simply the qualifier the fault was created with. Returns nil if fault isn't a aFault object.

See also:  - qualifier (EOEntity)

targetClassForFault:

+ (Class)targetClassForFault:aFault

Returns the class that will be instantiated when aFault is fetched. For a single-object fault the class is determined by the entity the fault was created with; for an array fault the class is NSMutableArray. Returns nil if aFault isn't a fault object.

See also:  - entity (EOQualfier)

Instance Methods

description

- (NSString *)description

Returns a string object that represents the contents of the fault object, without causing it to fetch its data. A single-object fault's description contains the name of its entity and the value of its primary key; an array fault's description contains the qualifier used to fetch its objects.

self

- self

Causes the fault object to fetch its data and return self. You can use this message to force a fault object to fetch its data immediately.